package com.sinosoft.hydra.um.services;

import com.sinosoft.hydra.um.LoginUser;
import com.sinosoft.hydra.um.condition.SearchDocumentCondition;
import com.sinosoft.hydra.um.constant.BaseConstant;
import com.sinosoft.hydra.um.domain.permission.*;
import cn.com.sinux.spring.exception.ServiceException;
import com.sinosoft.hydra.um.repositories.SysOrganizationRepository;
import com.sinosoft.hydra.um.repositories.SysUserRepository;
import com.sinosoft.hydra.um.repositories.TDocumentCopyDAO;
import com.sinosoft.hydra.um.repositories.TDocumentDAO;
import cn.com.sinux.spring.utils.FileUtils;
import cn.com.sinux.spring.utils.QueryHelper;
import cn.com.sinux.spring.utils.SpecificationHelper;
import cn.com.sinux.spring.utils.ValidatorUtils;;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import java.util.*;

/**
 * Created by Administrator on 2015/10/10.
 * 文档的维护
 */
@Service
public class DocumentService {

    @Autowired
    private TDocumentDAO tDocumentDAO;
    @Autowired
    private TDocumentCopyDAO tDocumentCopyDAO;
    @Autowired
    private SysUserRepository sysUserRepository;
    @Autowired
    private FileService fileService;

    private static final java.util.List<String> imageType = Arrays.asList("jpg", "png", "gif", "bmp");
    private static final java.util.List<String> officeType = Arrays.asList("xls", "xlsx", "ppt", "pptx", "doc", "docx", "pdf");
    private static final java.util.List<String> mediaType = Arrays.asList("mp3", "mp4", "ogg", "webm", "wav", "flv");

    /**
     * 添加文档
     *
     * @param tDocument
     * @param loginUser
     */
    @Transactional
    public TDocument addDocument(LoginUser loginUser, TDocument tDocument) {
        if (tDocument == null) {
            throw new ServiceException("数据传参不正确");
        }
        if (StringUtils.isBlank(tDocument.getAttachment())) {
            throw new ServiceException("文件上传失败");
        }
        tDocument.setCreateUser(loginUser);
        tDocument.setCreateTime(new Date());
        tDocument.setDownloadTimes(0);
        tDocument.setVersion(0);
        TDocumentCopy tDocumentCopy = new TDocumentCopy();
        tDocumentCopy.setDocNow(tDocument);
        tDocumentCopyDAO.save(tDocumentCopy);

        doConvertDocument(tDocument.getId(), tDocument.getAttachment());
        return tDocument;
        //
    }

    private void doConvertDocument(String id, String path){
        TFileConvert fileConvert = new TFileConvert();
        fileConvert.setSource(id);
        fileConvert.setSourceType(TDocument.class.getName());
        fileConvert.setSourcePath(path);

        fileService.convertFilesToSwf(fileConvert, null);
    }

    /**
     * 查询单个文档
     *
     * @param id
     * @return
     */
    public TDocument findDetail(String id){
        TDocument document = getOne(id);
        if(document == null){
            return document;
        }
        document.setFileConvert(fileService.findOne(document.getId(), TDocument.class.getName(), "swf"));
        return document;
    }

    /**
     * 判断文档类型
     * @param id
     * @return
     */
    public String findDetailType(String id){
        TDocument document = findDetail(id);
        if (document == null){
            return null;
        }
        String type = FileUtils.getExtName(document.getAttachment());
        if (imageType.contains(type)){
            return "IMAGE";
        }else if(officeType.contains(type)){
            return "OFFICE";
        }else if(mediaType.contains(type)){
            return "MEDIA";
        }else {
            return "UNDEFINED";
        }
    }

    /**
     * 获取单个文档
     *
     * @param id
     * @return
     */
    public TDocument getOne(String id) {
        return StringUtils.isBlank(id) ? null : tDocumentDAO.findOne(id);
    }

    /**
     * 获取详细的文档
     *
     * @param id
     * @return
     */
    public TDocumentCopy findOne(String id) {
        return StringUtils.isBlank(id) ? null : tDocumentCopyDAO.findOne(id);
    }

    /**
     * 修改文档
     *
     * @param tDocument
     */
    @Transactional
    public TDocument modifyDocument(String copyID, TDocument tDocument, LoginUser loginUser) {
        TDocumentCopy copy = findOne(copyID);
        tDocument.setCreateUser(copy.getDocNow().getCreateUser());
        tDocument.setCreateTime(copy.getDocNow().getCreateTime());
        tDocument.setUpdateUser(loginUser);
        tDocument.setUpdateTime(new Date());
        //如果已发布则生成新版本，未发布则修改原数据
        if (BaseConstant.DocStatus.DOC_STATUS_PUBLISHED.name().equals(copy.getDocNow().getDocStatus())){
            tDocument.setDownloadTimes(0);
            tDocument.setDocStatus(BaseConstant.DocStatus.DOC_STATUS_UN_PUBLISHED.name());
            tDocument.setVersion(copy.getDocNow().getVersion()+1);
            List<TDocument> history = copy.getDocHistory();
            history.add(copy.getDocNow());
            copy.setDocHistory(history);
            copy.setDocNow(tDocument);
            tDocumentCopyDAO.save(copy);
            doConvertDocument(copy.getDocNow().getId(), tDocument.getAttachment());
        } else {
            tDocument.setDownloadTimes(copy.getDocNow().getDownloadTimes());
            tDocument.setVersion(copy.getDocNow().getVersion());
//            tDocument.setFileConvert(copy.getDocNow().getFileConvert());
            tDocument.setDocStatus(copy.getDocNow().getDocStatus());
            tDocument.setId(copy.getDocNow().getId());
            //判断数据库里面文件的路径已经修改，则表示新上传了文件，需要清除原来转换的swf
            if (!tDocument.getAttachment().equals(copy.getDocNow().getAttachment())){
                fileService.removeConvert(tDocument.getId(), TDocument.class.getName());
                doConvertDocument(tDocument.getId(), tDocument.getAttachment());
            }
            tDocumentDAO.save(tDocument);
        }
        return tDocument;
    }

    /**
     * 批量删除文档
     *
     * @param ids
     */
    @Transactional
    public List<TDocument> delDocuments(List<String> ids) {
        if (ValidatorUtils.isArrayEmpty(ids)) {
            throw new ServiceException("参数错误");
        }
        List<TDocumentCopy> documentCopies = tDocumentCopyDAO.findAll(ids);
        List<TDocument> documents = new ArrayList<TDocument>();
        for (TDocumentCopy documentCopy : documentCopies) {
            if (BaseConstant.DocStatus.DOC_STATUS_UN_PUBLISHED.name().equals(documentCopy.getDocNow().getDocStatus())){
                if (ValidatorUtils.isArrayEmpty(documentCopy.getDocHistory())){
                    tDocumentCopyDAO.delete(documentCopy);
                    documents.add(documentCopy.getDocNow());
                    tDocumentDAO.delete(documentCopy.getDocNow());
                } else {
                    TDocument last = new TDocument();
                    List<TDocument> history = documentCopy.getDocHistory();
                    for (TDocument document : history) {
                        if (document.getVersion() == documentCopy.getDocNow().getVersion()-1){
                            last = document;
                        }
                    }
                    TDocument now = documentCopy.getDocNow();
                    documentCopy.setDocNow(last);
                    history.remove(last);
                    tDocumentCopyDAO.save(documentCopy);
                    documents.add(now);
                    tDocumentDAO.delete(now);
                }
            }
        }
        return documents;
    }

    /**
     * 修改下载次数
     *
     * @param id
     * @return
     */
    @Transactional
    public TDocument changeDownloadTimes(String id) {
        TDocument tDocument = getOne(id);
        if (tDocument == null) {
            throw new ServiceException("参数出错");
        }
        tDocument.setDownloadTimes(tDocument.getDownloadTimes() + 1);
        tDocumentDAO.save(tDocument);
        return tDocument;
    }

    /**
     * 批量发布文档
     *
     * @param ids
     * @param docStatus
     */
    @Transactional
    public List<TDocument> publishDocuments(List<String> ids, BaseConstant.DocStatus docStatus) {
        if (!BaseConstant.DocStatus.DOC_STATUS_PUBLISHED.equals(docStatus)) {
            docStatus = BaseConstant.DocStatus.DOC_STATUS_UN_PUBLISHED;
        }
        List<TDocument> documents = tDocumentDAO.findAll(ids);
        for (TDocument tDocument : documents) {
            tDocument.setDocStatus(docStatus.name());
        }
        tDocumentDAO.save(documents);
        return documents;
    }

    /**
     * 查询文档
     *
     * @param searchDocumentCondition
     * @param pageable
     * @return
     */
    public Page<TDocumentCopy> findDocuments(final SearchDocumentCondition searchDocumentCondition,Pageable pageable) {
        if (searchDocumentCondition == null) {
            return tDocumentCopyDAO.findAll(pageable);
        }
        Specification<TDocumentCopy> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDocumentCopy>() {

            public void fillParam(Root<TDocumentCopy> root, CriteriaBuilder cb, List<Predicate> list) {
                if (StringUtils.isNotBlank(searchDocumentCondition.getDocName())) {
                    list.add(cb.like(root.get("docNow").get("docName").as(String.class), "%" + searchDocumentCondition.getDocName() + "%"));
                }
                if (searchDocumentCondition.getModuleType() != null && StringUtils.isNotBlank(searchDocumentCondition.getModuleType().getId())) {
                    list.add(cb.equal(root.get("docNow").get("moduleType").get("id").as(String.class), searchDocumentCondition.getModuleType().getId()));
                }
                if (searchDocumentCondition.getDocBelong() != null && StringUtils.isNotBlank(searchDocumentCondition.getDocBelong().getId())) {
                    list.add(cb.equal(root.get("docNow").get("docBelong").get("id").as(String.class), searchDocumentCondition.getDocBelong().getId()));
                }
                if (StringUtils.isNotBlank(searchDocumentCondition.getDocKeyWord())) {
                    list.add(cb.like(root.get("docNow").get("docKeyWord").as(String.class), "%" + searchDocumentCondition.getDocKeyWord() + "%"));
                }
            }
        });
        return tDocumentCopyDAO.findAll(specification, pageable);
    }

    /**
     * 查询我的文档
     *
     * @param searchDocumentCondition
     * @param pageable
     * @return
     */
    public Page<TDocumentCopy> findMyDocuments(final SearchDocumentCondition searchDocumentCondition,final SysUserMember sysUserMember, Pageable pageable) {
        if (searchDocumentCondition == null) {
            return tDocumentCopyDAO.findAll(pageable);
        }
        Specification<TDocumentCopy> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TDocumentCopy>() {

            public void fillParam(Root<TDocumentCopy> root, CriteriaBuilder cb, List<Predicate> list) {
                if (StringUtils.isNotBlank(searchDocumentCondition.getDocName())) {
                    list.add(cb.like(root.get("docNow").get("docName").as(String.class), "%" + searchDocumentCondition.getDocName() + "%"));
                }
                if (searchDocumentCondition.getModuleType() != null && StringUtils.isNotBlank(searchDocumentCondition.getModuleType().getId())) {
                    list.add(cb.equal(root.get("docNow").get("moduleType").get("id").as(String.class), searchDocumentCondition.getModuleType().getId()));
                }
                if (searchDocumentCondition.getDocBelong() != null && StringUtils.isNotBlank(searchDocumentCondition.getDocBelong().getId())) {
                    list.add(cb.equal(root.get("docNow").get("docBelong").get("id").as(String.class), searchDocumentCondition.getDocBelong().getId()));
                }
                List<Predicate> predicates = new ArrayList<Predicate>();
                //我自己创建的文档所有
                Predicate self = cb.equal(root.get("docNow").get("createUser").get("id").as(String.class), sysUserMember.getId());
                //允许所有人可见的文档并已发布的文档
                Predicate toAll = cb.and(
                        cb.equal(root.get("docRangeType").as(String.class), BaseConstant.DocRangeType.ALL_USERS.getValue()),
                        cb.equal(root.get("docNow").get("docStatus").as(String.class), BaseConstant.DocStatus.DOC_STATUS_PUBLISHED.name())
                );
                predicates.add(self);
                predicates.add(toAll);
                if(ValidatorUtils.isArrayNotEmpty(sysUserMember.getSysOrganizationUsers())){
                    List<String> nIds = new ArrayList<String>();
                    List<String> rIds = new ArrayList<String>();
                    for(SysOrganizationUser sysOrganizationUser : sysUserMember.getSysOrganizationUsers()){
                        nIds.add(sysOrganizationUser.getSysOrganization().getId());
                        if(BaseConstant.INTEGER_TRUE.equals(sysOrganizationUser.getRole())){
                            rIds.add(sysOrganizationUser.getSysOrganization().getId());
                        }
                    }
                    //我所在部门的发布为部门可见的文档
                    Predicate toOrg = cb.and(
                            cb.equal(root.get("docRangeType").as(String.class), BaseConstant.DocRangeType.ONLY_ORG.getValue()),
                            root.get("docNow").get("docBelong").get("id").as(String.class).in(nIds),
                            cb.equal(root.get("docNow").get("docStatus").as(String.class), BaseConstant.DocStatus.DOC_STATUS_PUBLISHED.name())
                    );
                    predicates.add(toOrg);
                    //部门领导可见的包括所在部门用户发布的所有文档
                    if(ValidatorUtils.isArrayNotEmpty(rIds)){
                        Predicate toOrgLeader = cb.and(
                                root.get("docNow").get("docBelong").get("id").as(String.class).in(rIds),
                                cb.equal(root.get("docNow").get("docStatus").as(String.class), BaseConstant.DocStatus.DOC_STATUS_PUBLISHED.name())
                        );
                        predicates.add(toOrgLeader);
                    }
                }
                //设置为部分人员可见的文档
                Predicate toSomeUser = cb.and(
                        cb.equal(root.get("docNow").get("docStatus").as(String.class), BaseConstant.DocStatus.DOC_STATUS_PUBLISHED.name()),
                        cb.equal(root.get("docRangeType").as(String.class), BaseConstant.DocRangeType.SOME_USERS.getValue()),
                        cb.isMember(sysUserMember.getId(), root.get("visibleUsers").as(List.class))
                );
                predicates.add(toSomeUser);
                list.add(cb.or(predicates.toArray(new Predicate[predicates.size()])));
            }
        });
        return tDocumentCopyDAO.findAll(specification, pageable);
    }

    /**
     * 设置访问权限
     * @param id
     * @param docRangeType
     * @param userIds
     */
    public TDocument saveRange(String id, Integer docRangeType, List<String> userIds){
        TDocumentCopy tDocumentCopy = tDocumentCopyDAO.findOne(id);
        tDocumentCopy.setDocRangeType(docRangeType);
        if (docRangeType != BaseConstant.DocRangeType.SOME_USERS.getValue()){
            userIds = null;
        }
        tDocumentCopy.setVisibleUsers(sysUserRepository.findAll(userIds));
        tDocumentCopyDAO.save(tDocumentCopy);
        return tDocumentCopy.getDocNow();
    }

    /**
     * 所有版本的文档
     * @param id
     * @return
     */
    public List<TDocument> versionList(String id){
        TDocumentCopy copy = findCopyByDoc(id);
        List<TDocument> list = copy.getDocHistory();
        list.add(copy.getDocNow());
        return list;
    }

    /**
     * 查询详细文档
     *
     * @param id
     * @return
     */
    public TDocumentCopy findCopyByDoc(final String id){
        final TDocument document = getOne(id);
        List<TDocumentCopy> list = tDocumentCopyDAO.findAll();
        list = QueryHelper.doFilter(list, new QueryHelper.MatchWorker<TDocumentCopy>() {

            public boolean match(TDocumentCopy copy) {
                return copy.getDocNow().getId().equals(id) || copy.getDocHistory().contains(document);
            }
        });
        return list.get(0);
    }
}
